﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
using XnaTools;
using Microsoft.Xna.Framework;
using SStuff.XnaInterop;
using System.Runtime.Serialization.Json;
using Skinning;
using Microsoft.Xna.Framework.Silverlight;
using Microsoft.Xna.Framework.Graphics;
using Babylon.Toolbox;

namespace DudeSample
{
    public class Scene : BaseScene
    {
        OrbitCamera _camera;
        public Scene(DrawingSurface drawingSurface, FrameworkElement inputSurface)
            : base(drawingSurface, inputSurface)
        {
            _camera = new OrbitCamera();
            _camera.FarPlane = 100000;
            _camera.NearPlane = 0.1f;
            _camera.Radius = 150;
            _camera.Target = new Vector3(0,60,0);
            _camera.AttachTo(inputSurface);
            _lightDir0.Normalize();
            _lightDir1.Normalize();
            _lightDir2.Normalize();
        }

        InteropModel _dude;
        private Model _babyDude;
        AnimationPlayer _animPlayer;

        private float _specularPower = 8;

        public float SpecularPower
        {
            get { return _specularPower; }
            set { _specularPower = value; }
        }

        private float _specularAmount = 0.2f;

        public float SpecularAmount
        {
            get { return _specularAmount; }
            set { _specularAmount = value; }
        }

        private Color _specularColor = new Color(255, 240, 190, 255);

        public Color SpecularColor
        {
            get { return _specularColor; }
            set { _specularColor = value; }
        }

        private Vector3 _lightDir0 = new Vector3(0.7f, -0.5f, -0.7f);

        public Vector3 LightDir0
        {
            get { return _lightDir0; }
            set { _lightDir0 = value; }
        }

        private Vector3 _lightDir1 = new Vector3(-0.7f, -0.5f, -0.7f);

        public Vector3 LightDir1
        {
            get { return _lightDir1; }
            set { _lightDir1 = value; }
        }

        private Vector3 _lightDir2 = new Vector3(0, -0.5f, 0.7f);

        public Vector3 LightDir2
        {
            get { return _lightDir2; }
            set { _lightDir2 = value; }
        }

        Matrix[] _absoluteBones;
        
        protected override void OnLoaded(object sender, RoutedEventArgs e)
        {
            base.OnLoaded(sender, e);
            var gd = GraphicsDeviceManager.Current.GraphicsDevice;
            var dudeStream = Application.GetResourceStream(new Uri("Models/dude.bin", UriKind.Relative)).Stream;
            var dudeAnimStream = Application.GetResourceStream(new Uri("Models/dude_anim.json", UriKind.Relative)).Stream;
            _dude = InteropModel.FromBinaryReader(new System.IO.BinaryReader(dudeStream));
            _dude.Prepare(gd);
            _babyDude = _dude.ToBabylonModel(gd, (m, p) => {
                var skinnedEffect = new SkinnedEffect(gd);
                skinnedEffect.SceneAmbientColor = new Color(0.4f, 0.4f, 0.4f, 0.4f);
                skinnedEffect.AmbientColor = new Color(0.4f, 0.4f, 0.4f, 0.4f);
                skinnedEffect.SpecularColor = new Color(1.0f, 1.0f, 1.0f, 1.0f);
                skinnedEffect.SpecularPower = 12;
                skinnedEffect.Shininess = 0.5f;
                skinnedEffect.DiffuseTexture = p.IndexedTextureUsages["DiffuseTexture"].SL5Texture;
                skinnedEffect.BumpTexture = p.IndexedTextureUsages["BumpTexture"].SL5Texture;
                skinnedEffect.InvertBinormal = true;
                return skinnedEffect;
            });
            DataContractJsonSerializer s = new DataContractJsonSerializer(typeof(SkinningData));
            SkinningData skinningData = s.ReadObject(dudeAnimStream) as SkinningData;
            _animPlayer = new AnimationPlayer(skinningData);
            _animPlayer.StartClip(skinningData.AnimationClips["Take 001"]);

            _absoluteBones = new Matrix[_dude.Bones.Length];
            _dude.CopyAbsoluteBonesTo(_absoluteBones);
        }
        float _width, _height;
        protected override void OnSizeChanged(object sender, SizeChangedEventArgs e)
        {
            _width = (float)e.NewSize.Width;
            _height = (float)e.NewSize.Height;
            _camera.AspectRatio = _width / _height;
        }
        protected override void OnDraw(object sender, DrawEventArgs e)
        {
            _animPlayer.Update(e.DeltaTime, true, Matrix.Identity);
            var gd = e.GraphicsDevice;
            e.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, new Color(50, 100, 200, 255), 1, 0);
            
            _babyDude.Device = gd;
            Matrix world = Matrix.Identity;

            var skinData = _animPlayer.GetSkinTransforms();
            //AnimateModelAndComputeAbsoluteBones(e.TotalTime.TotalSeconds);

            // set common parameters (identics from on mesh part to another)
            
            
            
            foreach (var mesh in _babyDude.Meshes)
            {
                foreach (var effect in mesh.Effects){
                    var se = effect as SkinnedEffect;
                    se.Device = gd;
                    se.LightDir0 = _lightDir0;
                    se.LightDir1 = _lightDir1;
                    se.LightDir2 = _lightDir2;
                    se.SpecularPower = _specularPower;
                    se.Shininess = _specularAmount;
                    se.SpecularColor = _specularColor;
                    se.World = Matrix.Identity;
                    se.View = _camera.View;
                    se.Projection = _camera.Projection;
                    se.BonesSkin = skinData;
                    se.CameraPosition = _camera.Position;
                }
                
            }
            _camera.ApplyInertia();
            _babyDude.Draw();
            e.InvalidateSurface();
        }
    }
}
